/*
 * Acceleration.java
 *
 * Copyright 2008 the Desert Labs Project (http://desertlabs.us)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package us.desertlabs.physics;

import java.math.BigDecimal;
import us.desertlabs.number.BigUtility;

/**
 * Used to define rates of change of movement rates in multiple dimensions.
 *
 * @author Brandon Franklin
 */
public class Acceleration extends DimensionalValue {

    /**
     * Creates a new instance of <CODE>Acceleration</CODE> with the specified
     * rates of change.
     *
     * @param rates the rates of change in each dimension
     * @throws IllegalArgumentException if the parameter is null or contains any
     *         null elements
     */
    public Acceleration( final Number[] rates ) {
        super( rates );
    }

    /**
     * Returns the rates of change of rates of movement along all dimensions.
     *
     * @return the rates of change of rates of movement along all dimensions
     */
    public Number[] getRates() {
        return getValues();
    }

    /**
     * Given a <CODE>Velocity</CODE> and an amount of time, returns the <CODE>Velocity</CODE>
     * resulting from change based on this <CODE>Acceleration</CODE>.
     * Negative times <I>are</I> allowed.
     *
     * @param velocity the starting <CODE>Velocity</CODE>
     * @param time the amount of time over which the <CODE>Acceleration</CODE>
     *        should be applied
     * @return the resulting <CODE>Velocity</CODE>
     * @throws IllegalArgumentException if either of the parameters is invalid
     *         for any reason
     */
    public Velocity applyToVelocity( final Velocity velocity, final Time time ) {

        // Validate the velocity
        if( velocity == null ) {
            throw new IllegalArgumentException( "Velocity cannot be null." );
        } else if( !velocity.isValid() ) {
            throw new IllegalArgumentException( "Velocity is internally invalid." );
        } else if( velocity.getDimensionality() != getDimensionality() ) {
            throw new IllegalArgumentException( "Dimensionality of the Velocity does not match that of the Acceleration." );
        }

        // Validate the time
        if( time == null ) {
            throw new IllegalArgumentException( "Time cannot be null." );
        }

        // Do the adjustment
        final Number[] vRates = velocity.getRates();
        final Number[] rates = getRates();
        final BigDecimal bigDecTime = new BigDecimal( time.toString() );
        for( int i = 0; i < vRates.length; i++ ) {
            final BigDecimal bigDecVRate = new BigDecimal( vRates[i].toString() );
            final BigDecimal bigDecRate = new BigDecimal( rates[i].toString() );
            vRates[i] = BigUtility.clipScale( bigDecVRate.add( bigDecRate.multiply( bigDecTime ) ) );
        }

        return new Velocity( vRates );
    }
}
